﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Windows.Forms;
using DigitalRune.Windows.TextEditor;
using DigitalRune.Windows.TextEditor.Completion;
using DigitalRune.Windows.TextEditor.Highlighting;
using Zove.Query;
using Zove.Runtime;
using DigitalRune.Windows.TextEditor.Selection;
using FunctionalCLR.Core.Logging;

namespace Zove.Desktop {
    public partial class QueryWindow : AbstractDesktopForm {

        public string Content {
            get {
                return this.tbQuery.Text;
            }
            set {
                this.tbQuery.Text = value;
            }
        }

        private Query.Query d;

        public override string GetColouringScheme() {
            return "SQL";
        }

        BackgroundWorker backgroundWorker1 = null;

        public QueryWindow()
            : base() {
            this.tbQuery.Document.HighlightingStrategy
                = HighlightingManager.Manager.FindHighlighter("SQL");

            backgroundWorker1 = new BackgroundWorker();
            backgroundWorker1.DoWork +=
                new DoWorkEventHandler
                    (backgroundWorker1_DoWork);
            backgroundWorker1.RunWorkerCompleted +=
                new RunWorkerCompletedEventHandler(
                    backgroundWorker1_RunWorkerCompleted);
            backgroundWorker1.ProgressChanged +=
                new ProgressChangedEventHandler(
                    backgroundWorker1_ProgressChanged);

            this.gvResult.ContextMenuStrip = new ContextMenuStrip();
            this.gvResult.ContextMenuStrip.Items.Add(
                "Show Reasoning Log", null,
                new EventHandler(ShowReasoningLog));
            this.gvResult.ContextMenuStrip.Items.Add(
                "&Copy", null,
                new EventHandler(Copy));
            this.gvResult.ContextMenuStrip.Items.Add(
                "&Copy Solution", null,
                new EventHandler(CopySolution));
        }

        public void ShowReasoningLog(object sender, EventArgs args) {
            DataGridViewRow row = this.gvResult.Rows[
                this.gvResult.SelectedCells[0].RowIndex];
            DataGridViewCell cell = row.Cells[0];

            RuntimeFactor rf = d.Model.GetFactorByName(cell.Value.ToString());
            if (rf != null) {
                ResolutionLogWindow w = new ResolutionLogWindow(rf);

                w.MdiParent = this.MdiParent;
                w.Show();
                w.Show(rf);
            }
        }

        public void Copy(object sender, EventArgs args) {
            Clipboard.SetText(this.gvResult.SelectedCells[0].Value.ToString());
        }

        public void CopySolution(object sender, EventArgs args) {
            
        }

        public override TextEditorControl GetTextEditorControl() {
            return this.tbQuery;
        }

        public QueryWindow(string fileName)
            : this() {
            if (!File.Exists(fileName)) {
                throw new FileNotFoundException(fileName);
            }

            this.Text = fileName;
            this.FileName = fileName;
            this.tbQuery.Text = File.ReadAllText(fileName);
        }

        public void CodeCompletionRequest(object sender, CompletionEventArgs e) {
            if (e.Key == '.') {
                string k = string.Empty;
                int index, c = this.tbQuery.ActiveTextAreaControl.TextArea.Caret.Column;
                for (index = c - 1; index > 0; index--) {
                    char m = this.tbQuery.Text[index];
                    if (!char.IsLetterOrDigit(m) && m != '.') {
                        break;
                    }
                }
                k = this.tbQuery.Text.Substring(index, c - index);

                this.tbQuery.ShowCompletionWindow(
                    new CodeCompletionDataProvider(k), e.Key, true);
            }

            if (this.tbQuery.CompletionWindowVisible) {
                return;
            }

            if (e.Key == '\0') {
                this.tbQuery.ShowCompletionWindow(
                    new CodeCompletionDataProvider(), e.Key, false);
            } else if (char.IsLetter(e.Key)) {
                this.tbQuery.ShowCompletionWindow(
                    new CodeCompletionDataProvider(), e.Key, true);
            }
        }

        public string LastWhereClause {
            get;
            set;
        }

        public string WhereClause {
            get {
                string[] tokens = this.tbQuery.Document.TextContent.Split(' ');
                if (tokens.Length < 2) {
                    return string.Empty;
                }

                for (int index = tokens.Length - 1; index >= 0; index--) {
                    if (string.Compare(
                    tokens[index], "where", false) == 0) {
                        return tokens[index + 1];
                    }
                }

                return string.Empty;
            }
        }

        public override string GetFileExtension() {
            return ".zql";
        }

        public override void Execute() {
            string query = string.Empty;

            if (string.IsNullOrEmpty(
                this.tbQuery.ActiveTextAreaControl.TextArea.SelectionManager.SelectedText)) {
                query = this.tbQuery.Document.TextContent;
            } else {
                query = this.tbQuery.ActiveTextAreaControl.TextArea.SelectionManager.SelectedText;
            }

            if (!query.EndsWith(";")) {
                query = query + ";";
            }

            this.query = query;

            //if (!backgroundWorker1.IsBusy) {
            //backgroundWorker1.RunWorkerAsync();
            QueryManager queryManager = new QueryManager();
            d = queryManager.CreateQuery(query);

            try {
                results = d.Run();

                this.gvResult.Rows.Clear();
                foreach (QueryResult result in results) {
                    this.gvResult.Rows.Add(new string[]{
                    result.Item, result.Value, result.Unit, result.Solution
                });
                }
            } catch (ModelLoadingException ex) {
                StreamWriter sw = File.AppendText(@"C:\logging.txt");
                foreach (LoggingMessage message in ex.ErrorMessages) {
                    sw.WriteLine("File: {0}\tLine:{1}\tDesc:{2}",
                        message.FileName, message.LineNumber, message.Description);
                }
                sw.Close();
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
                StreamWriter sw = File.AppendText(@"C:\logging.txt");
                sw.WriteLine("File: {0}\tMessage:{1}\tTrace:{2}",
                    ex.Source, ex.Message, ex.StackTrace);
                sw.Close();
            }
        }

        public override string GetFileFilter() {
            return "Zoom Query Language file (*.zql) | *.zql";
        }

        private string query = string.Empty;

        private List<QueryResult> results = null;

        public void backgroundWorker1_DoWork(object sender, EventArgs e) {
            QueryManager queryManager = new QueryManager();
            Query.Query d = queryManager.CreateQuery(query);

            try {
                results = d.Run();

                this.gvResult.Rows.Clear();
                foreach (QueryResult result in results) {
                    this.gvResult.Rows.Add(new string[]{
                    result.Item, result.Value, result.Solution
                });
                }
            } catch (ModelLoadingException ex) {
                StreamWriter sw = File.AppendText(@"C:\logging.txt");
                foreach (LoggingMessage message in ex.ErrorMessages) {
                    sw.WriteLine("File: {0}\tLine:{1}\tDesc:{2}",
                        message.FileName, message.LineNumber, message.Description);
                }
            }
        }

        private Exception ex;

        public void backgroundWorker1_RunWorkerCompleted(
            object sender, EventArgs e) {
            if (ex == null) {
                this.gvResult.Rows.Clear();
                foreach (QueryResult result in results) {
                    this.gvResult.Rows.Add(new string[]{
                    result.Item, result.Value, result.Solution
                });
                }
            } else {
                MessageBox.Show("Please check logging file, errors were catched.");
            }
        }

        public void backgroundWorker1_ProgressChanged(
            object sender, EventArgs e) {
        }
    }
}
